# -*- coding: utf-8 -*-
"""
投资组合服务模块
提供投资组合创建、管理和持仓数据生成的功能
"""

from datetime import date, timedelta
from decimal import Decimal
from typing import List, Dict, Optional

from django.db import transaction
from django.core.exceptions import ValidationError

from .models import Portfolio, Position, AssetInfo, Valuation, Indicator


class PortfolioService:
    """投资组合服务类"""
    
    @staticmethod
    def create_portfolio(
        portfolio_code: str,
        portfolio_name: str,
        portfolio_type: int = 1,
        portfolio_status: int = 1,
        establish_date: Optional[date] = None,
        maturity_date: Optional[date] = None
    ) -> Portfolio:
        """
        创建投资组合
        
        Args:
            portfolio_code: 投资组合代码 (唯一)
            portfolio_name: 投资组合名称
            portfolio_type: 投资组合类型 (默认1)
            portfolio_status: 投资组合状态 (默认1)
            establish_date: 成立日期 (默认今天)
            maturity_date: 到期日期 (默认1年后)
            
        Returns:
            Portfolio: 创建的投资组合实例
            
        Raises:
            ValidationError: 当投资组合代码已存在时
        """
        if establish_date is None:
            establish_date = date.today()
        
        if maturity_date is None:
            maturity_date = establish_date + timedelta(days=365)
        
        # 检查投资组合代码是否已存在
        qs = Portfolio.objects.filter(portfolio_code=portfolio_code)
        if qs.exists():
            print(f"投资组合代码 '{portfolio_code}' 已存在，先删除再创建")
            qs.delete()
            pass

        with transaction.atomic():
            portfolio = Portfolio.objects.create(
                portfolio_code=portfolio_code,
                portfolio_name=portfolio_name,
                portfolio_type=portfolio_type,
                portfolio_status=portfolio_status,
                establish_date=establish_date,
                maturity_date=maturity_date
            )
            
            return portfolio
    
    @staticmethod
    def generate_position_data(
        portfolio_code: str,
        valuation_date: date,
        asset_count: int = 5
    ) -> List[Position]:
        """
        生成组合持仓数据
        
        Args:
            portfolio_code: 投资组合代码
            valuation_date: 估值日期
            asset_count: 生成资产数量 (默认5个)
            
        Returns:
            List[Position]: 生成的持仓数据列表
            
        Raises:
            ValidationError: 当投资组合不存在时
        """
        # 检查投资组合是否存在
        try:
            portfolio = Portfolio.objects.get(portfolio_code=portfolio_code)
        except Portfolio.DoesNotExist:
            raise ValidationError(f"投资组合 '{portfolio_code}' 不存在")
        
        # 预定义一些模拟资产数据
        sample_assets = [
            {"code": "000001", "name": "平安银行", "type": "stock"},
            {"code": "000002", "name": "万科A", "type": "stock"},
            {"code": "600036", "name": "招商银行", "type": "stock"},
            {"code": "000858", "name": "五粮液", "type": "stock"},
            {"code": "002415", "name": "海康威视", "type": "stock"},
            {"code": "123456", "name": "国债2024", "type": "bond"},
            {"code": "234567", "name": "企业债A", "type": "bond"},
            {"code": "345678", "name": "可转债B", "type": "bond"},
            {"code": "510300", "name": "沪深300ETF", "type": "fund"},
            {"code": "159915", "name": "创业板ETF", "type": "fund"},
        ]
        
        positions = []
        
        with transaction.atomic():
            # 清除该组合在该日期的现有持仓数据
            Position.objects.filter(
                portfolio_code_id=portfolio_code,
                valuation_date=valuation_date
            ).delete()
            
            # 生成新的持仓数据
            import random
            
            for i in range(min(asset_count, len(sample_assets))):
                asset = sample_assets[i]
                
                # 生成随机数据
                quantity = Decimal(str(random.randint(100, 10000)))
                price = Decimal(str(random.uniform(10, 100)))
                market_value = quantity * price
                
                position = Position.objects.create(
                    portfolio_code_id=portfolio_code,  # 使用外键ID
                    valuation_date=valuation_date,
                    position_code=asset["code"],
                    position_name=asset["name"],
                    position_type=asset["type"],
                    quantity=quantity,
                    amount=market_value,  # 金额等于市值
                    market_value=market_value
                )
                
                positions.append(position)
        
        return positions
    
    @staticmethod
    def generate_valuation_data(
        portfolio_code: str,
        valuation_date: date
    ) -> Valuation:
        """
        生成估值数据
        
        Args:
            portfolio_code: 投资组合代码
            valuation_date: 估值日期
            
        Returns:
            Valuation: 创建的估值数据
        """
        valuation, created = Valuation.objects.get_or_create(
            portfolio_code_id=portfolio_code,
            valuation_date=valuation_date
        )
        
        return valuation
    
    @staticmethod
    def generate_indicator_data(
        portfolio_code: str,
        valuation_date: date,
        asset_scope: str = "all"
    ) -> Indicator:
        """
        生成指标数据
        
        Args:
            portfolio_code: 投资组合代码
            valuation_date: 估值日期
            asset_scope: 资产范围 (默认"all")
            
        Returns:
            Indicator: 创建的指标数据
        """
        import random
        
        # 计算总资产（基于持仓数据）
        positions = Position.objects.filter(
            portfolio_code_id=portfolio_code,
            valuation_date=valuation_date
        )
        
        total_amount = sum(pos.market_value for pos in positions) or Decimal("1000000")
        net_amount = total_amount  # 简化处理，假设无负债
        
        # 生成随机指标数据
        leverage = Decimal(str(random.uniform(1.0, 1.5)))
        sharpe_ratio = Decimal(str(random.uniform(0.5, 2.0)))
        modified_duration = Decimal(str(random.uniform(1.0, 5.0)))
        ytm = Decimal(str(random.uniform(0.02, 0.08)))  # 2%-8%
        pvbp = Decimal(str(random.uniform(0.001, 0.01)))
        
        indicator, created = Indicator.objects.get_or_create(
            portfolio_code_id=portfolio_code,
            valuation_date=valuation_date,
            asset_scope=asset_scope,
            defaults={
                'total_amount': total_amount,
                'net_amount': net_amount,
                'leverage': leverage,
                'sharpe_ratio': sharpe_ratio,
                'modified_duration': modified_duration,
                'YTM': ytm,
                'PVBP': pvbp
            }
        )
        
        if not created:
            # 更新现有记录
            indicator.total_amount = total_amount
            indicator.net_amount = net_amount
            indicator.leverage = leverage
            indicator.sharpe_ratio = sharpe_ratio
            indicator.modified_duration = modified_duration
            indicator.YTM = ytm
            indicator.PVBP = pvbp
            indicator.save()
        
        return indicator
    
    @staticmethod
    def initialize_portfolio_with_data(
        portfolio_code: str,
        portfolio_name: str,
        valuation_date: Optional[date] = None
    ) -> Dict:
        """
        初始化投资组合并生成完整数据
        
        Args:
            portfolio_code: 投资组合代码
            portfolio_name: 投资组合名称
            valuation_date: 估值日期 (默认今天)
            
        Returns:
            Dict: 包含创建的所有数据的字典
        """
        if valuation_date is None:
            valuation_date = date.today()
        
        # 创建投资组合
        portfolio = PortfolioService.create_portfolio(
            portfolio_code=portfolio_code,
            portfolio_name=portfolio_name
        )
        
        # 生成持仓数据
        positions = PortfolioService.generate_position_data(
            portfolio_code=portfolio_code,
            valuation_date=valuation_date
        )
        
        # 生成估值数据
        valuation = PortfolioService.generate_valuation_data(
            portfolio_code=portfolio_code,
            valuation_date=valuation_date
        )
        
        # 生成指标数据
        indicator = PortfolioService.generate_indicator_data(
            portfolio_code=portfolio_code,
            valuation_date=valuation_date
        )
        
        return {
            'portfolio': portfolio,
            'positions': positions,
            'valuation': valuation,
            'indicator': indicator
        }